package com.the_last.service.impl;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.the_last.constant.RedisKeyConstant;
import com.the_last.listener.ProductImportListener;
import com.the_last.mapper.ProductMapper;
import com.the_last.pojo.dto.ProductExportDTO;
import com.the_last.pojo.dto.ProductImportDTO;
import com.the_last.pojo.po.Product;
import com.the_last.pojo.po.ProductCategory;
import com.the_last.pojo.vo.ProductImportVO;
import com.the_last.service.ProductCategoryService;
import com.the_last.service.ProductService;
import com.the_last.utils.ExcelUtil;
import com.the_last.utils.RedisUtil;
import com.the_last.utils.Result;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zhanghaifeng
 * @description 针对表【product】的数据库操作Service实现
 * @createDate 2025-06-06 23:26:45
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product>
        implements ProductService {
    
    private final RedisUtil redisUtil;
    private final RedissonClient redissonClient;
    private final ProductCategoryService productCategoryService;
    private final ExcelUtil excelUtil;
    
    @Override
    public Result<Product> getProductWithCache(Integer id) {
        if (id == null) {
            return Result.fail("商品ID不能为空");
        }
        
        String idStr = id.toString();
        List<String> singleIdList = Collections.singletonList(idStr);
        
        // 复用批量查询方法
        Map<String, Product> productInfoMap = getProductInfoMap(singleIdList);
        Map<String, Integer> salesMap = getSalesMap(singleIdList);
        Map<String, Integer> stockMap = getStockMap(singleIdList);
        
        Product product = productInfoMap.get(idStr);
        if (product == null) {
            return Result.fail("商品不存在");
        }
        
        // 设置最新的销量和库存
        product.setSales(salesMap.getOrDefault(idStr, 0));
        product.setStock(stockMap.getOrDefault(idStr, 0));
        
        return Result.success(product);
    }
    
    @Override
    public Result<List<Product>> getProductListWithCache(Boolean filterZeroStock) {
        List<String> idList = getProductIdList();
        Map<String, Product> productInfoMap = getProductInfoMap(idList);
        Map<String, Integer> salesMap = getSalesMap(idList);
        Map<String, Integer> stockMap = getStockMap(idList);
        
        List<Product> result = new ArrayList<>();
        for (String id : idList) {
            Product p = productInfoMap.get(id);
            if (p == null) continue;
            
            p.setSales(salesMap.getOrDefault(id, 0));
            p.setStock(stockMap.getOrDefault(id, 0));
            
            if (!Boolean.TRUE.equals(filterZeroStock) || p.getStock() > 0) {
                result.add(p);
            }
        }
        
        return Result.success(result);
    }
    
    /**
     * 获取商品 ID 列表
     */
    private List<String> getProductIdList() {
        List<String> idList = redisUtil.getList(RedisKeyConstant.PRODUCT_ID_LIST);
        if (CollectionUtils.isEmpty(idList)) {
            // 获取分布式锁防止缓存击穿
            RLock lock = redissonClient.getLock(RedisKeyConstant.PRODUCT_LIST_LOCK);
            try {
                lock.lock();
                
                // 二次检查
                idList = redisUtil.getList(RedisKeyConstant.PRODUCT_ID_LIST);
                if (CollectionUtils.isEmpty(idList)) {
                    // 从数据库拉全量商品 ID
                    List<Product> dbProducts = list();
                    idList = dbProducts.stream()
                            .map(product -> product.getId().toString())
                            .collect(Collectors.toList());
                    // 缓存 ID 列表
                    if (!CollectionUtils.isEmpty(idList)) {
                        redisUtil.setList(RedisKeyConstant.PRODUCT_ID_LIST, idList);
                    }
                }
            } finally {
                if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                    lock.unlock();
                }
            }
        }
        return idList;
    }
    
    /**
     * 获取商品基本信息（按 ID 批量获取）
     */
    private Map<String, Product> getProductInfoMap(List<String> idList) {
        if (CollectionUtils.isEmpty(idList)) {
            return new HashMap<>();
        }
        
        Map<String, String> cacheMap = redisUtil.hMGet(RedisKeyConstant.PRODUCT_INFO_KEY, idList);
        Map<String, Product> result = new HashMap<>();
        
        List<String> missingIds = new ArrayList<>();
        for (String id : idList) {
            String json = cacheMap.get(id);
            if (json != null && !json.isEmpty()) {
                try {
                    result.put(id, JSON.parseObject(json, Product.class));
                } catch (Exception e) {
                    log.warn("解析商品信息缓存失败, id: {}", id, e);
                    missingIds.add(id);
                }
            } else {
                missingIds.add(id);
            }
        }
        
        if (!missingIds.isEmpty()) {
            // DB 回源 - 使用批量设置缓存
            List<Integer> missingIntIds = missingIds.stream()
                    .map(Integer::valueOf)
                    .collect(Collectors.toList());
            List<Product> dbProducts = listByIds(missingIntIds);
            
            if (!CollectionUtils.isEmpty(dbProducts)) {
                // 准备批量缓存数据
                Map<String, String> batchCacheData = new HashMap<>();
                for (Product p : dbProducts) {
                    String id = p.getId().toString();
                    result.put(id, p);
                    batchCacheData.put(id, JSON.toJSONString(p));
                }
                
                // 批量设置缓存
                if (!batchCacheData.isEmpty()) {
                    redisUtil.hMSet(RedisKeyConstant.PRODUCT_INFO_KEY, batchCacheData);
                }
            }
        }
        
        return result;
    }
    
    /**
     * 获取销量（按 ID 批量获取）
     */
    private Map<String, Integer> getSalesMap(List<String> idList) {
        if (CollectionUtils.isEmpty(idList)) {
            return new HashMap<>();
        }
        
        Map<String, String> cacheMap = redisUtil.hMGet(RedisKeyConstant.PRODUCT_SALES_KEY, idList);
        Map<String, Integer> result = new HashMap<>();
        
        List<String> missingIds = new ArrayList<>();
        for (String id : idList) {
            String sales = cacheMap.get(id);
            if (sales != null && !sales.isEmpty()) {
                try {
                    result.put(id, Integer.valueOf(sales));
                } catch (NumberFormatException e) {
                    log.warn("解析销量缓存失败, id: {}, sales: {}", id, sales, e);
                    missingIds.add(id);
                }
            } else {
                missingIds.add(id);
            }
        }
        
        if (!missingIds.isEmpty()) {
            // DB 回源 - 使用批量设置缓存
            Map<String, Integer> dbSalesMap = getSalesFromDb(missingIds);
            if (!dbSalesMap.isEmpty()) {
                result.putAll(dbSalesMap);
                
                // 准备批量缓存数据
                Map<String, String> batchCacheData = dbSalesMap.entrySet().stream()
                        .collect(Collectors.toMap(
                                Map.Entry::getKey,
                                e -> e.getValue().toString()
                        ));
                
                // 批量设置缓存
                redisUtil.hMSet(RedisKeyConstant.PRODUCT_SALES_KEY, batchCacheData);
            }
        }
        
        return result;
    }
    
    /**
     * 获取库存（按 ID 批量获取）
     */
    private Map<String, Integer> getStockMap(List<String> idList) {
        if (CollectionUtils.isEmpty(idList)) {
            return new HashMap<>();
        }
        
        Map<String, String> cacheMap = redisUtil.hMGet(RedisKeyConstant.PRODUCT_STOCK_KEY, idList);
        Map<String, Integer> result = new HashMap<>();
        
        List<String> missingIds = new ArrayList<>();
        for (String id : idList) {
            String stock = cacheMap.get(id);
            if (stock != null && !stock.isEmpty()) {
                try {
                    result.put(id, Integer.valueOf(stock));
                } catch (NumberFormatException e) {
                    log.warn("解析库存缓存失败, id: {}, stock: {}", id, stock, e);
                    missingIds.add(id);
                }
            } else {
                missingIds.add(id);
            }
        }
        
        if (!missingIds.isEmpty()) {
            // DB 回源 - 使用批量设置缓存
            Map<String, Integer> dbStockMap = getStockFromDb(missingIds);
            if (!dbStockMap.isEmpty()) {
                result.putAll(dbStockMap);
                
                // 准备批量缓存数据
                Map<String, String> batchCacheData = dbStockMap.entrySet().stream()
                        .collect(Collectors.toMap(
                                Map.Entry::getKey,
                                e -> e.getValue().toString()
                        ));
                
                // 批量设置缓存
                redisUtil.hMSet(RedisKeyConstant.PRODUCT_STOCK_KEY, batchCacheData);
            }
        }
        
        return result;
    }
    
    /**
     * 从数据库获取销量数据
     */
    private Map<String, Integer> getSalesFromDb(List<String> idList) {
        if (CollectionUtils.isEmpty(idList)) {
            return new HashMap<>();
        }
        
        List<Integer> intIds = idList.stream()
                .map(Integer::valueOf)
                .collect(Collectors.toList());
        
        List<Product> products = listByIds(intIds);
        return products.stream()
                .collect(Collectors.toMap(
                        p -> p.getId().toString(),
                        p -> p.getSales() != null ? p.getSales() : 0
                ));
    }
    
    /**
     * 从数据库获取库存数据
     */
    private Map<String, Integer> getStockFromDb(List<String> idList) {
        if (CollectionUtils.isEmpty(idList)) {
            return new HashMap<>();
        }
        
        List<Integer> intIds = idList.stream()
                .map(Integer::valueOf)
                .collect(Collectors.toList());
        
        List<Product> products = listByIds(intIds);
        return products.stream()
                .collect(Collectors.toMap(
                        p -> p.getId().toString(),
                        p -> p.getStock() != null ? p.getStock() : 0
                ));
    }
    
    @Override
    public Result<Void> addProduct(Product product) {
        try {
            // 参数校验
            if (product == null) {
                return Result.fail("商品信息不能为空");
            }
            if (product.getName() == null || product.getName().trim().isEmpty()) {
                return Result.fail("商品名称不能为空");
            }
            if (product.getCategoryId() == null) {
                return Result.fail("商品分类不能为空");
            }
            if (product.getCurrentPrice() == null || product.getCurrentPrice().compareTo(java.math.BigDecimal.ZERO) < 0) {
                return Result.fail("商品价格不能为空且必须大于等于0");
            }
            if (product.getStock() == null || product.getStock() < 0) {
                return Result.fail("库存数量不能为空且必须大于等于0");
            }
            
            // 设置默认值
            if (product.getSales() == null) {
                product.setSales(0);
            }
            product.setDeleted(0);
            
            // 保存到数据库
            boolean success = save(product);
            if (!success) {
                return Result.fail("新增商品失败");
            }
            
            redisUtil.delete(RedisKeyConstant.PRODUCT_ID_LIST);
            
            log.info("新增商品成功，商品ID: {}, 商品名称: {}", product.getId(), product.getName());
            return Result.success();
        } catch (Exception e) {
            log.error("新增商品失败", e);
            return Result.fail("新增商品失败：" + e.getMessage());
        }
    }
    
    @Override
    public Result<Void> updateProduct(Product product) {
        try {
            // 参数校验
            if (product == null || product.getId() == null) {
                return Result.fail("商品ID不能为空");
            }
            
            // 检查商品是否存在
            Product existingProduct = getById(product.getId());
            if (existingProduct == null) {
                return Result.fail("商品不存在");
            }
            
            // 校验必要字段
            if (product.getName() != null && product.getName().trim().isEmpty()) {
                return Result.fail("商品名称不能为空");
            }
            if (product.getCurrentPrice() != null && product.getCurrentPrice().compareTo(java.math.BigDecimal.ZERO) < 0) {
                return Result.fail("商品价格必须大于等于0");
            }
            if (product.getStock() != null && product.getStock() < 0) {
                return Result.fail("库存数量必须大于等于0");
            }
            
            // 只更新非空字段
            if (product.getName() != null) {
                existingProduct.setName(product.getName());
            }
            if (product.getImageUrl() != null) {
                existingProduct.setImageUrl(product.getImageUrl());
            }
            if (product.getCategoryId() != null) {
                existingProduct.setCategoryId(product.getCategoryId());
            }
            if (product.getStock() != null) {
                existingProduct.setStock(product.getStock());
            }
            if (product.getCurrentPrice() != null) {
                existingProduct.setCurrentPrice(product.getCurrentPrice());
            }
            
            // 更新数据库
            boolean success = updateById(existingProduct);
            if (!success) {
                return Result.fail("更新商品失败");
            }
            // 清除该商品的特定缓存
            clearSpecificProductCache(product.getId());
            
            log.info("更新商品成功，商品ID: {}, 商品名称: {}", product.getId(), existingProduct.getName());
            return Result.success();
            
        } catch (Exception e) {
            log.error("更新商品失败", e);
            return Result.fail("更新商品失败：" + e.getMessage());
        }
    }
    
    @Override
    public Result<Void> deleteProduct(Integer id) {
        try {
            if (id == null) {
                return Result.fail("商品ID不能为空");
            }
            
            // 检查商品是否存在
            Product product = getById(id);
            if (product == null) {
                return Result.fail("商品不存在");
            }
            
            // 逻辑删除
            product.setDeleted(1);
            boolean success = updateById(product);
            if (!success) {
                return Result.fail("删除商品失败");
            }
            
            redisUtil.delete(RedisKeyConstant.PRODUCT_ID_LIST);
            
            log.info("删除商品成功，商品ID: {}, 商品名称: {}", id, product.getName());
            return Result.success();
            
        } catch (Exception e) {
            log.error("删除商品失败", e);
            return Result.fail("删除商品失败：" + e.getMessage());
        }
    }
    
    @Override
    public Result<ProductImportVO> importProducts(MultipartFile file) {
        ProductImportVO result = new ProductImportVO();
        
        try {
            // 文件校验
            if (file == null || file.isEmpty()) {
                return Result.fail("上传文件不能为空");
            }
            
            // 使用ExcelUtil进行文件格式验证
            if (!excelUtil.verifyExcel(file.getOriginalFilename())) {
                return Result.fail(excelUtil.EXCEL_FORMAT_PATTERN_ERROR);
            }
            
            // 文件大小校验（10MB）
            if (!excelUtil.verifyFileSize(file, 10)) {
                return Result.fail("文件大小不能超过10MB");
            }
            
            // 创建监听器
            ProductImportListener listener = new ProductImportListener(this, productCategoryService);
            
            // 使用ExcelUtil异步读取Excel文件
            excelUtil.readMultipartFileAsync(file, ProductImportDTO.class, listener);
            
            // 构建结果
            List<Product> validProducts = listener.getValidProducts();
            List<String> errorMessages = listener.getErrorMessages();
            
            result.setTotalRows(validProducts.size() + errorMessages.size());
            result.setSuccessCount(validProducts.size());
            result.setFailCount(errorMessages.size());
            result.setErrorMessages(errorMessages);
            
            // 清除缓存
            if (!validProducts.isEmpty()) {
                redisUtil.delete(RedisKeyConstant.PRODUCT_ID_LIST);
            }
            
            log.info("商品Excel导入完成，总行数: {}, 成功: {}, 失败: {}",
                    result.getTotalRows(), result.getSuccessCount(), result.getFailCount());
            
            return Result.success(result);
            
        } catch (Exception e) {
            log.error("商品Excel导入失败", e);
            return Result.fail("导入失败：" + e.getMessage());
        }
    }
    
    @Override
    public void syncProductDataFromRedisToDatabase() {
        log.info("开始同步Redis中的商品数据到数据库");
        
        try {
            // 获取所有商品ID
            List<String> productIds = getProductIdList();
            if (CollectionUtils.isEmpty(productIds)) {
                log.warn("未找到商品ID列表，同步任务结束");
                return;
            }
            
            // 获取Redis中的销量和库存数据
            Map<String, String> salesMap = redisUtil.hGetAll(RedisKeyConstant.PRODUCT_SALES_KEY);
            Map<String, String> stockMap = redisUtil.hGetAll(RedisKeyConstant.PRODUCT_STOCK_KEY);
            
            if (salesMap.isEmpty() && stockMap.isEmpty()) {
                log.info("Redis中没有需要同步的销量和库存数据");
                return;
            }
            
            // 批量获取数据库中的商品信息
            List<Integer> intIds = productIds.stream()
                    .map(Integer::valueOf)
                    .collect(Collectors.toList());
            List<Product> dbProducts = listByIds(intIds);
            
            if (CollectionUtils.isEmpty(dbProducts)) {
                log.warn("数据库中未找到商品数据");
                return;
            }
            
            // 创建商品映射，便于快速查找
            Map<Integer, Product> productMap = dbProducts.stream()
                    .collect(Collectors.toMap(Product::getId, p -> p));
            
            List<Product> productsToUpdate = new ArrayList<>();
            int totalProducts = productIds.size();
            int errorCount = 0;
            
            // 遍历所有商品ID，检查是否需要更新
            for (String productIdStr : productIds) {
                try {
                    Integer productId = Integer.valueOf(productIdStr);
                    Product product = productMap.get(productId);
                    
                    if (product == null) {
                        log.warn("商品不存在，跳过同步，productId: {}", productId);
                        errorCount++;
                        continue;
                    }
                    
                    boolean needUpdate = false;
                    Integer oldSales = product.getSales();
                    Integer oldStock = product.getStock();
                    
                    // 检查销量是否需要更新
                    String redisSales = salesMap.get(productIdStr);
                    if (redisSales != null) {
                        Integer newSales = Integer.valueOf(redisSales);
                        if (!newSales.equals(oldSales)) {
                            product.setSales(newSales);
                            needUpdate = true;
                            log.debug("商品销量需要更新，productId: {}, oldSales: {}, newSales: {}",
                                    productId, oldSales, newSales);
                        }
                    }
                    
                    // 检查库存是否需要更新
                    String redisStock = stockMap.get(productIdStr);
                    if (redisStock != null) {
                        Integer newStock = Integer.valueOf(redisStock);
                        if (!newStock.equals(oldStock)) {
                            product.setStock(newStock);
                            needUpdate = true;
                            log.debug("商品库存需要更新，productId: {}, oldStock: {}, newStock: {}",
                                    productId, oldStock, newStock);
                        }
                    }
                    
                    // 如果有变更，加入批量更新列表
                    if (needUpdate) {
                        productsToUpdate.add(product);
                    }
                    
                } catch (NumberFormatException e) {
                    errorCount++;
                    log.error("商品ID格式错误，跳过同步，productId: {}", productIdStr, e);
                } catch (Exception e) {
                    errorCount++;
                    log.error("处理商品数据时发生异常，productId: {}", productIdStr, e);
                }
            }
            
            // 批量更新数据库
            int syncCount = 0;
            if (!productsToUpdate.isEmpty()) {
                try {
                    boolean batchUpdateResult = updateBatchById(productsToUpdate);
                    if (batchUpdateResult) {
                        syncCount = productsToUpdate.size();
                        log.info("批量更新商品数据成功，更新数量: {}", syncCount);
                    } else {
                        log.error("批量更新商品数据失败");
                        errorCount += productsToUpdate.size();
                    }
                } catch (Exception e) {
                    log.error("批量更新商品数据时发生异常", e);
                    errorCount += productsToUpdate.size();
                }
            }
            
            log.info("商品数据同步完成，总计处理: {} 个商品，成功同步: {} 个，失败: {} 个",
                    totalProducts, syncCount, errorCount);
            
        } catch (Exception e) {
            log.error("同步商品数据到数据库时发生异常", e);
            throw new RuntimeException("商品数据同步失败", e);
        }
    }
    
    /**
     * 清除特定商品的缓存
     *
     * @param productId 商品ID
     */
    private void clearSpecificProductCache(Integer productId) {
        if (productId == null) {
            return;
        }
        
        try {
            String productIdStr = productId.toString();
            
            // 清除该商品在Hash中的缓存
            redisUtil.removeFromHash(RedisKeyConstant.PRODUCT_INFO_KEY, productIdStr);
            redisUtil.removeFromHash(RedisKeyConstant.PRODUCT_SALES_KEY, productIdStr);
            redisUtil.removeFromHash(RedisKeyConstant.PRODUCT_STOCK_KEY, productIdStr);
            
            log.debug("特定商品缓存清除成功，productId: {}", productId);
        } catch (Exception e) {
            log.warn("清除特定商品缓存失败，productId: {}", productId, e);
        }
    }
    
    @Override
    public void exportProducts(HttpServletResponse response) {
        try {
            log.info("开始导出商品数据");
            
            // 获取所有商品数据（不过滤库存为0的商品）
            Result<List<Product>> productListResult = getProductListWithCache(false);
            if (productListResult.getCode() != 200) {
                throw new RuntimeException("获取商品列表失败：" + productListResult.getMsg());
            }
            
            List<Product> products = productListResult.getData();
            if (CollectionUtils.isEmpty(products)) {
                log.warn("没有商品数据可导出");
                throw new RuntimeException("没有商品数据可导出");
            }
            
            // 获取所有商品分类信息，构建分类映射
            List<ProductCategory> categories = productCategoryService.list();
            Map<Integer, String> categoryMap = categories.stream()
                    .collect(Collectors.toMap(ProductCategory::getId, ProductCategory::getName));
            
            // 转换为导出DTO
            List<ProductExportDTO> exportData = products.stream()
                    .map(product -> {
                        ProductExportDTO dto = new ProductExportDTO();
                        dto.setId(product.getId() != null ? product.getId().toString() : "");
                        dto.setName(product.getName() != null ? product.getName() : "");
                        dto.setCategoryId(product.getCategoryId() != null ? product.getCategoryId().toString() : "");
                        dto.setCategoryName(categoryMap.getOrDefault(product.getCategoryId(), ""));
                        dto.setCurrentPrice(product.getCurrentPrice() != null ? product.getCurrentPrice().toString() : "0");
                        dto.setStock(product.getStock() != null ? product.getStock().toString() : "0");
                        dto.setSales(product.getSales() != null ? product.getSales().toString() : "0");
                        dto.setImageUrl(product.getImageUrl() != null ? product.getImageUrl() : "");
                        return dto;
                    })
                    .collect(Collectors.toList());
            
            // 使用ExcelUtil导出Excel
            String fileName = "商品列表_" + java.time.LocalDateTime.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"));
            excelUtil.writeToResponse(fileName, "商品数据", ProductExportDTO.class, exportData, response);
            
            log.info("商品数据导出完成，导出数量: {}", exportData.size());
            
        } catch (Exception e) {
            log.error("导出商品数据失败", e);
            throw new RuntimeException("导出商品数据失败：" + e.getMessage());
        }
    }
}




